Collection Types

Swift provides three primary collection types, known as arrays, sets, and dictionaries, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.

../_images/CollectionTypes_intro_2x.png

Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you can’t insert a value of the wrong type into a collection by mistake. It also means you can be confident about the type of values you will retrieve from a collection.

Note

Swift’s array, set, and dictionary types are implemented as generic collections. For more about generic types and collections, see Generics.

Mutability of Collections

If you create an array, a set, or a dictionary, and assign it to a variable, the collection that’s created will be mutable. This means that you can change (or mutate) the collection after it’s created by adding, removing, or changing items in the collection. If you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents can’t be changed.

Note

It’s good practice to create immutable collections in all cases where the collection doesn’t need to change. Doing so makes it easier for you to reason about your code and enables the Swift compiler to optimize the performance of the collections you create.

Arrays

An array stores values of the same type in an ordered list. The same value can appear in an array multiple times at different positions.

Note

Swift’s Array type is bridged to Foundation’s NSArray class.

For more information about using Array with Foundation and Cocoa, see Bridging Between Array and NSArray.

Array Type Shorthand Syntax

The type of a Swift array is written in full as Array<Element>, where Element is the type of values the array is allowed to store. You can also write the type of an array in shorthand form as [Element]. Although the two forms are functionally identical, the shorthand form is preferred and is used throughout this guide when referring to the type of an array.

Creating an Empty Array

You can create an empty array of a certain type using initializer syntax:

  1. var someInts = [Int]()
  2. print("someInts is of type [Int] with \(someInts.count) items.")
  3. // Prints "someInts is of type [Int] with 0 items."

Note that the type of the someInts variable is inferred to be [Int] from the type of the initializer.

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty array with an empty array literal, which is written as [] (an empty pair of square brackets):

  1. someInts.append(3)
  2. // someInts now contains 1 value of type Int
  3. someInts = []
  4. // someInts is now an empty array, but is still of type [Int]

Creating an Array with a Default Value

Swift’s Array type also provides an initializer for creating an array of a certain size with all of its values set to the same default value. You pass this initializer a default value of the appropriate type (called repeating): and the number of times that value is repeated in the new array (called count):

  1. var threeDoubles = Array(repeating: 0.0, count: 3)
  2. // threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

Creating an Array by Adding Two Arrays Together

You can create a new array by adding together two existing arrays with compatible types with the addition operator (+). The new array’s type is inferred from the type of the two arrays you add together:

  1. var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
  2. // anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]
  3. var sixDoubles = threeDoubles + anotherThreeDoubles
  4. // sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

Creating an Array with an Array Literal

You can also initialize an array with an array literal, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets:

  1. [value 1, value 2, value 3]

The example below creates an array called shoppingList to store String values:

  1. var shoppingList: [String] = ["Eggs", "Milk"]
  2. // shoppingList has been initialized with two initial items

The shoppingList variable is declared as “an array of string values”, written as [String]. Because this particular array has specified a value type of String, it’s allowed to store String values only. Here, the shoppingList array is initialized with two String values ("Eggs" and "Milk"), written within an array literal.

Note

The shoppingList array is declared as a variable (with the var introducer) and not a constant (with the let introducer) because more items are added to the shopping list in the examples below.

In this case, the array literal contains two String values and nothing else. This matches the type of the shoppingList variable’s declaration (an array that can only contain String values), and so the assignment of the array literal is permitted as a way to initialize shoppingList with two initial items.

Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of shoppingList could have been written in a shorter form instead:

  1. var shoppingList = ["Eggs", "Milk"]

Because all values in the array literal are of the same type, Swift can infer that [String] is the correct type to use for the shoppingList variable.

Accessing and Modifying an Array

You access and modify an array through its methods and properties, or by using subscript syntax.

To find out the number of items in an array, check its read-only count property:

  1. print("The shopping list contains \(shoppingList.count) items.")
  2. // Prints "The shopping list contains 2 items."

Use the Boolean isEmpty property as a shortcut for checking whether the count property is equal to 0:

  1. if shoppingList.isEmpty {
  2. print("The shopping list is empty.")
  3. } else {
  4. print("The shopping list isn't empty.")
  5. }
  6. // Prints "The shopping list isn't empty."

You can add a new item to the end of an array by calling the array’s append(_:) method:

  1. shoppingList.append("Flour")
  2. // shoppingList now contains 3 items, and someone is making pancakes

Alternatively, append an array of one or more compatible items with the addition assignment operator (+=):

  1. shoppingList += ["Baking Powder"]
  2. // shoppingList now contains 4 items
  3. shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
  4. // shoppingList now contains 7 items

Retrieve a value from the array by using subscript syntax, passing the index of the value you want to retrieve within square brackets immediately after the name of the array:

  1. var firstItem = shoppingList[0]
  2. // firstItem is equal to "Eggs"

Note

The first item in the array has an index of 0, not 1. Arrays in Swift are always zero-indexed.

You can use subscript syntax to change an existing value at a given index:

  1. shoppingList[0] = "Six eggs"
  2. // the first item in the list is now equal to "Six eggs" rather than "Eggs"

When you use subscript syntax, the index you specify needs to be valid. For example, writing shoppingList[shoppingList.count] = "Salt" to try to append an item to the end of the array results in a runtime error.

You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces "Chocolate Spread", "Cheese", and "Butter" with "Bananas" and "Apples":

  1. shoppingList[4...6] = ["Bananas", "Apples"]
  2. // shoppingList now contains 6 items

To insert an item into the array at a specified index, call the array’s insert(_:at:) method:

  1. shoppingList.insert("Maple Syrup", at: 0)
  2. // shoppingList now contains 7 items
  3. // "Maple Syrup" is now the first item in the list

This call to the insert(_:at:) method inserts a new item with a value of "Maple Syrup" at the very beginning of the shopping list, indicated by an index of 0.

Similarly, you remove an item from the array with the remove(at:) method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you don’t need it):

  1. let mapleSyrup = shoppingList.remove(at: 0)
  2. // the item that was at index 0 has just been removed
  3. // shoppingList now contains 6 items, and no Maple Syrup
  4. // the mapleSyrup constant is now equal to the removed "Maple Syrup" string

Note

If you try to access or modify a value for an index that’s outside of an array’s existing bounds, you will trigger a runtime error. You can check that an index is valid before using it by comparing it to the array’s count property. The largest valid index in an array is count - 1 because arrays are indexed from zero—however, when count is 0 (meaning the array is empty), there are no valid indexes.

Any gaps in an array are closed when an item is removed, and so the value at index 0 is once again equal to "Six eggs":

  1. firstItem = shoppingList[0]
  2. // firstItem is now equal to "Six eggs"

If you want to remove the final item from an array, use the removeLast() method rather than the remove(at:) method to avoid the need to query the array’s count property. Like the remove(at:) method, removeLast() returns the removed item:

  1. let apples = shoppingList.removeLast()
  2. // the last item in the array has just been removed
  3. // shoppingList now contains 5 items, and no apples
  4. // the apples constant is now equal to the removed "Apples" string

Iterating Over an Array

You can iterate over the entire set of values in an array with the for-in loop:

  1. for item in shoppingList {
  2. print(item)
  3. }
  4. // Six eggs
  5. // Milk
  6. // Flour
  7. // Baking Powder
  8. // Bananas

If you need the integer index of each item as well as its value, use the enumerated() method to iterate over the array instead. For each item in the array, the enumerated() method returns a tuple composed of an integer and the item. The integers start at zero and count up by one for each item; if you enumerate over a whole array, these integers match the items’ indices. You can decompose the tuple into temporary constants or variables as part of the iteration:

  1. for (index, value) in shoppingList.enumerated() {
  2. print("Item \(index + 1): \(value)")
  3. }
  4. // Item 1: Six eggs
  5. // Item 2: Milk
  6. // Item 3: Flour
  7. // Item 4: Baking Powder
  8. // Item 5: Bananas

For more about the for-in loop, see For-In Loops.

Sets

A set stores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items isn’t important, or when you need to ensure that an item only appears once.

Note

Swift’s Set type is bridged to Foundation’s NSSet class.

For more information about using Set with Foundation and Cocoa, see Bridging Between Set and NSSet.

Hash Values for Set Types

A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that’s the same for all objects that compare equally, such that if a == b, the hash value of a is equal to the hash value of b.

All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default, and can be used as set value types or dictionary key types. Enumeration case values without associated values (as described in Enumerations) are also hashable by default.

Note

You can use your own custom types as set value types or dictionary key types by making them conform to the Hashable protocol from the Swift standard library. For information about implementing the required hash(into:) method, see Hashable. For information about conforming to protocols, see Protocols.

Set Type Syntax

The type of a Swift set is written as Set<Element>, where Element is the type that the set is allowed to store. Unlike arrays, sets don’t have an equivalent shorthand form.

Creating and Initializing an Empty Set

You can create an empty set of a certain type using initializer syntax:

  1. var letters = Set<Character>()
  2. print("letters is of type Set<Character> with \(letters.count) items.")
  3. // Prints "letters is of type Set<Character> with 0 items."

Note

The type of the letters variable is inferred to be Set<Character>, from the type of the initializer.

Alternatively, if the context already provides type information, such as a function argument or an already typed variable or constant, you can create an empty set with an empty array literal:

  1. letters.insert("a")
  2. // letters now contains 1 value of type Character
  3. letters = []
  4. // letters is now an empty set, but is still of type Set<Character>

Creating a Set with an Array Literal

You can also initialize a set with an array literal, as a shorthand way to write one or more values as a set collection.

The example below creates a set called favoriteGenres to store String values:

  1. var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
  2. // favoriteGenres has been initialized with three initial items

The favoriteGenres variable is declared as “a set of String values”, written as Set<String>. Because this particular set has specified a value type of String, it’s only allowed to store String values. Here, the favoriteGenres set is initialized with three String values ("Rock", "Classical", and "Hip hop"), written within an array literal.

Note

The favoriteGenres set is declared as a variable (with the var introducer) and not a constant (with the let introducer) because items are added and removed in the examples below.

A set type can’t be inferred from an array literal alone, so the type Set must be explicitly declared. However, because of Swift’s type inference, you don’t have to write the type of the set’s elements if you’re initializing it with an array literal that contains values of just one type. The initialization of favoriteGenres could have been written in a shorter form instead:

  1. var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

Because all values in the array literal are of the same type, Swift can infer that Set<String> is the correct type to use for the favoriteGenres variable.

Accessing and Modifying a Set

You access and modify a set through its methods and properties.

To find out the number of items in a set, check its read-only count property:

  1. print("I have \(favoriteGenres.count) favorite music genres.")
  2. // Prints "I have 3 favorite music genres."

Use the Boolean isEmpty property as a shortcut for checking whether the count property is equal to 0:

  1. if favoriteGenres